package com.assistant.ai;

import com.assistant.core.Config;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.time.Duration;
import java.util.Base64;

/**
 * @author Anyang
 * @version 1.0.0
 * @date 2025/10/25 05:10:37
 * @description 语音识别模块
 */
public class STTModule {
    private static final Logger logger = LoggerFactory.getLogger(STTModule.class);
    private final HttpClient httpClient;
    private final Gson gson;

    // STT 依赖于 NLUModule 已经获取到的 Access Token
    private final TTSModule ttsModule;

    public STTModule(TTSModule ttsModule) {
        this.ttsModule = ttsModule;
        this.httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .connectTimeout(Duration.ofSeconds(10))
                .build();
        this.gson = new Gson();
    }

    /**
     * 将指定的音频文件转换为文本。
     * * @param audioFilePath 音频文件路径（例如：test.wav）
     * @return 识别出的文本，如果失败返回 null。
     */
    public String recognizeSpeech(String audioFilePath) {
        if (Config.ENABLE_MOCK) {
            logger.warn("【STT模块】Mock模式已启用，不执行 API 调用。");
            return mockRecognition(audioFilePath);
        }

        try {
            // 1. 读取音频文件并进行 Base64 编码
            File audioFile = new File(audioFilePath);
            if (!audioFile.exists()) {
                logger.error("【STT错误】音频文件不存在: {}", audioFilePath);
                return null;
            }
            byte[] audioBytes = Files.readAllBytes(audioFile.toPath());
            String base64Audio = Base64.getEncoder().encodeToString(audioBytes);

            // 2. 构建 JSON 请求体
            JsonObject jsonBody = new JsonObject();
            jsonBody.addProperty("format", "wav"); // 假设音频格式为 wav
            jsonBody.addProperty("rate", 16000);   // 假设采样率为 16000
            jsonBody.addProperty("channel", 1);     // 假设通道数为 1
            jsonBody.addProperty("cuid", "assistant_client"); // 客户端ID
            jsonBody.addProperty("token", ttsModule.getAccessToken()); // 使用 NLU 获取的 Token
            jsonBody.addProperty("dev_pid", 1537); // 普通话输入法模型
            jsonBody.addProperty("speech", base64Audio);
            jsonBody.addProperty("len", audioBytes.length);

            // 3. 发送 POST 请求
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(Config.BAIDU_STT_URL))
                    .header("Content-Type", "application/json")
                    .POST(HttpRequest.BodyPublishers.ofString(jsonBody.toString()))
                    .build();

            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            // 4. 解析响应
            if (response.statusCode() != 200) {
                logger.error("【STT API错误】API 调用失败，状态码: {}, 响应体: {}", response.statusCode(), response.body());
                return null;
            }

            JsonObject responseJson = gson.fromJson(response.body(), JsonObject.class);

            // 检查错误码
            if (responseJson.get("err_no").getAsInt() != 0) {
                logger.error("【STT API错误】STT服务返回错误码: {}，消息: {}",
                        responseJson.get("err_no").getAsInt(), responseJson.get("err_msg").getAsString());
                return null;
            }

            // 提取识别结果
            if (responseJson.has("result") && responseJson.getAsJsonArray("result").size() > 0) {
                String resultText = responseJson.getAsJsonArray("result").get(0).getAsString();
                logger.info("【STT识别成功】文本: {}", resultText);
                return resultText;
            }

            return null;
        } catch (IOException | InterruptedException e) {
            logger.error("【STT调用失败】发生网络或IO错误", e);
            return null;
        }
    }

    /**
     * 启用 Mock 模式时的模拟识别结果。
     */
    private String mockRecognition(String audioFilePath) {
        // 根据测试用例模拟不同的语音输入
        if (audioFilePath.contains("test_open_app.wav")) {
            return "打开我的QQ";
        } else if (audioFilePath.contains("test_open_url.wav")) {
            return "在浏览器里打开哔哩哔哩的网站";
        } else if (audioFilePath.contains("test_write_article.wav")) {
            return "帮我写一篇关于人工智能的文章";
        }
        return "模拟语音输入，请打开浏览器";
    }
    /**
     * 【新增】将原始 PCM 音频字节数组转换为文本。
     * @param audioData 16kHz, 16bit, mono PCM 数据
     * @return 识别出的文本，如果失败返回 null。
     */
    public String recognizeSpeech(byte[] audioData) {
        if (Config.ENABLE_MOCK) {
            logger.warn("【STT模块】Mock模式已启用，不执行 API 调用。");
            return "模拟语音输入，请打开浏览器"; // 简化 Mock
        }

        if (audioData == null || audioData.length == 0) {
            logger.error("【STT错误】音频数据为空。");
            return null;
        }

        try {
            // 1. 进行 Base64 编码
            String base64Audio = Base64.getEncoder().encodeToString(audioData);

            // 2. 构建 JSON 请求体
            JsonObject jsonBody = new JsonObject();
            jsonBody.addProperty("format", "pcm"); // 【修改】格式现在是 pcm
            jsonBody.addProperty("rate", 16000);   // 采样率为 16000
            jsonBody.addProperty("channel", 1);     // 通道数为 1
            jsonBody.addProperty("cuid", "assistant_client"); // 客户端ID
            jsonBody.addProperty("token", ttsModule.getAccessToken()); // 使用 NLU 获取的 Token
            jsonBody.addProperty("dev_pid", 1537); // 普通话输入法模型
            jsonBody.addProperty("speech", base64Audio);
            jsonBody.addProperty("len", audioData.length);

            // 3. 发送 POST 请求
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(Config.BAIDU_STT_URL))
                    .header("Content-Type", "application/json")
                    .POST(HttpRequest.BodyPublishers.ofString(jsonBody.toString()))
                    .build();

            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            // 4. 解析响应
            if (response.statusCode() != 200) {
                logger.error("【STT API错误】API 调用失败，状态码: {}, 响应体: {}", response.statusCode(), response.body());
                return null;
            }

            JsonObject responseJson = gson.fromJson(response.body(), JsonObject.class);

            // 检查错误码
            if (responseJson.get("err_no").getAsInt() != 0) {
                logger.error("【STT API错误】STT服务返回错误码: {}，消息: {}",
                        responseJson.get("err_no").getAsInt(), responseJson.get("err_msg").getAsString());
                return null;
            }

            // 提取识别结果
            if (responseJson.has("result") && responseJson.getAsJsonArray("result").size() > 0) {
                String resultText = responseJson.getAsJsonArray("result").get(0).getAsString();
                logger.info("【STT识别成功】文本: {}", resultText);
                return resultText;
            }

            return null;
        } catch (IOException | InterruptedException e) {
            logger.error("【STT调用失败】发生网络或IO错误", e);
            Thread.currentThread().interrupt(); // 【修正】
            return null;
        }
    }
}